#include "pch.h"
#include "CSocketClientManager.h"
#include "CSocketClientFactory.h"

CSocketClientManager::CSocketClientManager() :
	m_bClose(false), m_tpHandlePool(20)
{
	::InitializeCriticalSection(&m_csLock);
}
bool CSocketClientManager::AddSocketClient(CSocketClient* pSocketClient)
{
	::EnterCriticalSection(&m_csLock);
	if (m_bClose) {
		::LeaveCriticalSection(&m_csLock);
		return false;
	}
	m_lstSocketClient.push_back(pSocketClient);
	::LeaveCriticalSection(&m_csLock);
	return true;
}
bool CSocketClientManager::RemoveSocketClient(CSocketClient* pSocketClient)
{
	bool bFind = false;
	::EnterCriticalSection(&m_csLock);
	list<CSocketClient*>::iterator it = m_lstSocketClient.begin();
	for (; it != m_lstSocketClient.end(); it++)
	{
		if (*it == pSocketClient)
		{
			bFind = true;
			break;
		}
	}
	if (bFind)m_lstSocketClient.remove(pSocketClient);
	::LeaveCriticalSection(&m_csLock);
	return bFind;
}

bool CSocketClientManager::HandleSocketProc(SOCKETDESOBJ socketDesObj, PSOCKETOBJ pSocketObj,HANDLE hThread)
{
	PSOCKETCLIENTCLASSOBJ pSocketClientClassObj = CSocketClientFactory::getInstance().getClassByType(socketDesObj.desType);
	if (pSocketClientClassObj == NULL)return false;
	CSocketClient* pSocketClient = pSocketClientClassObj->method();
	pSocketClient->m_pClassObj = pSocketClientClassObj;
	pSocketClient->m_pSocketObj = pSocketObj;
	pSocketClient->m_sckDes = socketDesObj;
	bool bAccept;
	if (bAccept = pSocketClient->PreAccept())
	{
		if (!OnAcceptSocketClient(pSocketClient, pSocketClient->m_pClassObj->clientType, pSocketClient->m_iId))
		{
			return false;
		}
	}
	if (pSocketClient->PreProcessEvent())
	{
		int nEnumRet;
		while (TRUE)
		{
			int nIndex = ::WSAWaitForMultipleEvents(1, &pSocketObj->hEvent, FALSE, WSA_INFINITE, FALSE);
			if (nIndex == WSA_WAIT_FAILED)
			{
				pSocketClient->OnWaitEventsFail(nIndex);
				break;
			}
			else if (nIndex == WSA_WAIT_TIMEOUT)
			{
				continue;
			}
			else
			{
				nIndex = nIndex - WSA_WAIT_EVENT_0;
				WSANETWORKEVENTS wsaNetEvent;
				if ((nEnumRet = ::WSAEnumNetworkEvents(pSocketObj->s, pSocketObj->hEvent, &wsaNetEvent)) == SOCKET_ERROR)
				{
					pSocketClient->OnEnumNetworkEventsFail(WSAGetLastError());
				}
				if (!pSocketClient->m_bActive) {
					break;
				}
				if (nEnumRet != SOCKET_ERROR) {
					if (wsaNetEvent.lNetworkEvents & FD_CONNECT)
					{
						pSocketClient->OnConnect(wsaNetEvent.iErrorCode[FD_CONNECT_BIT]);
					}
					if (wsaNetEvent.lNetworkEvents & FD_READ)
					{
						pSocketClient->OnRead(wsaNetEvent.iErrorCode[FD_READ_BIT]);
					}
					if (wsaNetEvent.lNetworkEvents & FD_CLOSE)
					{
						pSocketClient->OnClose(wsaNetEvent.iErrorCode[FD_CLOSE_BIT]);
					}
					if (wsaNetEvent.lNetworkEvents & FD_WRITE)
					{
						pSocketClient->m_bSendData = false;
						pSocketClient->OnSend(wsaNetEvent.iErrorCode[FD_WRITE_BIT]);
					}
					if (pSocketClient->m_bSendData)
					{
						pSocketClient->m_bSendData = false;
						pSocketClient->OnSend(NULL);
					}
				}
			}
		}
	}
	pSocketClient->PreDiscard();
	if (bAccept)
	{
		OnDiscardSocketClient(pSocketClient, pSocketClient->m_pClassObj->clientType, pSocketClient->m_iId);
	}
	else
	{
		delete pSocketClient;
	}
	return true;
}

typedef struct ST_THREAD_SOCKETCLIENT_PARAM {
	CSocketClientManager* pSocketManager;
	PSOCKETOBJ pSocket;
	HANDLE hThread;
	void* selectParam;
}THREAD_SOCKETCLIENT_PARAM, *PTHREAD_SOCKETCLIENT_PARAM;

unsigned __stdcall _ThreadProcSocketClient(void* arg)
{
	THREAD_SOCKETCLIENT_PARAM* param = (THREAD_SOCKETCLIENT_PARAM*)arg;
	PSOCKETOBJ pSocket = param->pSocket;

	SOCKETDESOBJ socketDesObj;
	bool bGetSocketDes = param->pSocketManager->GetSocketClientType(socketDesObj, pSocket, param->selectParam);
	if (bGetSocketDes) 
	{
		param->pSocketManager->HandleSocketProc(socketDesObj, pSocket, param->hThread);
	}
	delete param;
	return 0;
}


bool CSocketClientManager::StartSocketClientThread(PSOCKETOBJ pSocketObj, void* selectParam, bool bAutoReleaseThread)
{
	if (m_bClose)
	{
		return false;
	}
	PTHREAD_SOCKETCLIENT_PARAM param = new THREAD_SOCKETCLIENT_PARAM;
	param->pSocketManager = this;
	param->pSocket = pSocketObj;
	param->hThread = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	param->selectParam = selectParam;
	bool bExecute = m_tpHandlePool.Execute(_ThreadProcSocketClient, param, param->hThread, bAutoReleaseThread);

	if (!bExecute) {
		delete param;
	}
	return bExecute;
}

bool CSocketClientManager::GetSocketClientType(SOCKETDESOBJ& socketDesObj, PSOCKETOBJ pSocketObj, void* selectParam)
{
	return false;
}

bool CSocketClientManager::OnAcceptSocketClient(CSocketClient* pSocketClient, int type, int id) {
	if (!AddSocketClient(pSocketClient)) {
		delete pSocketClient;
		return false;
	}
	return true;
}

void CSocketClientManager::OnDiscardSocketClient(CSocketClient* pSocketClient, int type, int id) {
	if (RemoveSocketClient(pSocketClient))
	{
		delete pSocketClient;
	}
}

void CSocketClientManager::CloseAllServer()
{
	::EnterCriticalSection(&m_csLock);
	m_bClose = true;
	list<CSocketClient*>::iterator it = m_lstSocketClient.begin();
	for (; it != m_lstSocketClient.end(); it++)
	{
		CloseSocketClient(*it);
	}
	m_lstSocketClient.clear();
	::LeaveCriticalSection(&m_csLock);
	m_tpHandlePool.Shutdown();
}
void CSocketClientManager::CloseSocketClient(CSocketClient* pSocketClient)
{
	pSocketClient->Shutdown();
}